use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use lazy_static::lazy_static;
use log::info;
use sea_orm::DbConn;
use serde::{Deserialize, Serialize};

use crate::config::SystemConf;
use crate::error::MyError;

#[derive(Clone, Serialize, Deserialize)]
pub struct Dict {
    pub id: i64,
    pub name: String,
    pub code: String,
    pub value: String,
    pub children: Option<Vec<Dict>>,
}

pub struct CtxState {
    pub db: HashMap<String, Arc<DbConn>>,
    pub system_conf: Option<Arc<SystemConf>>,
    pub dict: Option<HashMap<String, Arc<(Vec<Dict>, Vec<Dict>)>>>,
}

lazy_static! {
    static ref CTX_STATE: Arc<RwLock<CtxState>> = Arc::new(RwLock::new(CtxState {
        db: HashMap::default(),
        system_conf: None,
        dict: None,
    }));
}

pub fn get_ctx_state_read() -> Result<RwLockReadGuard<'static, CtxState>, MyError> {
    Ok(CTX_STATE.read().unwrap())
}

pub fn get_ctx_state_write() -> Result<RwLockWriteGuard<'static, CtxState>, MyError> {
    Ok(CTX_STATE.write().unwrap())
}

pub fn get_db() -> Result<Arc<DbConn>, MyError> {
    let ctx_state = get_ctx_state_read()?;
    let db = &ctx_state.db.get("default");
    match db {
        None => Err(MyError::ServerError("default db is empty".to_string())),
        Some(db) => Ok(Arc::clone(db)),
    }
}

pub fn get_db_by_key(key: &str) -> Result<Arc<DbConn>, MyError> {
    let ctx_state = get_ctx_state_read()?;
    let db = &ctx_state.db.get(key);
    match db {
        None => Err(MyError::ServerError(format!("[{}] db is empty", key))),
        Some(db) => Ok(Arc::clone(db)),
    }
}

pub fn set_db(db: Option<DbConn>) -> Result<(), MyError> {
    match db {
        None => Err(MyError::ServerError("db is empty".to_string())),
        Some(db) => {
            let mut ctx_state = get_ctx_state_write()?;
            ctx_state.db.insert("default".to_string(), Arc::from(db));
            Ok(())
        }
    }
}

pub fn set_db_by_key(key: String, db: Option<DbConn>) -> Result<(), MyError> {
    match db {
        None => Err(MyError::ServerError(format!("[{}] db is empty", key))),
        Some(db) => {
            let mut ctx_state = get_ctx_state_write()?;
            ctx_state.db.insert(key, Arc::from(db));
            Ok(())
        }
    }
}

pub fn get_system_conf() -> Result<Arc<SystemConf>, MyError> {
    let ctx_state = get_ctx_state_read()?;
    match &ctx_state.system_conf {
        None => Err(MyError::ServerError("system conf is empty".to_string())),
        Some(conf) => Ok(Arc::clone(conf)),
    }
}

pub fn set_system_conf(conf: Option<SystemConf>) -> Result<(), MyError> {
    match conf {
        None => Err(MyError::ServerError("system conf is empty".to_string())),
        Some(conf) => {
            let mut ctx_state = get_ctx_state_write()?;
            ctx_state.system_conf = Some(Arc::from(conf));
            Ok(())
        }
    }
}

pub fn set_dict_conf(
    dict: Option<HashMap<String, Arc<(Vec<Dict>, Vec<Dict>)>>>,
) -> Result<(), MyError> {
    match dict {
        None => Err(MyError::ServerError("dict conf is empty".to_string())),
        Some(_) => {
            info!(">>>>>>>>>> 更新字典信息 <<<<<<<<<<");
            let mut ctx_state = get_ctx_state_write()?;
            ctx_state.dict = dict;
            Ok(())
        }
    }
}

pub fn get_dict_by_group_code(code: &str) -> Result<Arc<(Vec<Dict>, Vec<Dict>)>, MyError> {
    let ctx_state = get_ctx_state_read()?;
    match &ctx_state.dict {
        None => Err(MyError::ServerError("dict conf is empty".to_string())),
        Some(dict) => {
            let dict_vec = dict.get(code);
            match &dict_vec {
                None => Err(MyError::ServerError(format!(
                    "dict group [{}] is empty ",
                    code
                ))),
                Some(dict_vec) => Ok(Arc::clone(dict_vec)),
            }
        }
    }
}
